
using OfficeOpenXml;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;
using UnityEngine;
using Valve.Newtonsoft.Json;
using Valve.Newtonsoft.Json.Linq;

namespace HHHFramework {
    public sealed class Vector3SerializationSurrogate : ISerializationSurrogate
    {
        public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
        {
            Vector3 v3 = (Vector3)obj;
            info.AddValue("x", v3.x);
            info.AddValue("y", v3.y);
            info.AddValue("z", v3.z);
        }

        public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
        {
            Vector3 v3 = (Vector3)obj;
            v3.x = info.GetSingle("x");
            v3.y = info.GetSingle("y");
            v3.z = info.GetSingle("z");
            obj = v3;
            return obj;
        }
    }
    class QuaternionSerializationSurrogate : ISerializationSurrogate
    {
        public void GetObjectData(object obj, SerializationInfo info, StreamingContext context)
        {
            Quaternion q = (Quaternion)obj;
            info.AddValue("x", q.x);
            info.AddValue("y", q.y);
            info.AddValue("z", q.z);
            info.AddValue("w", q.w);
        }

        public object SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
        {
            Quaternion q = (Quaternion)obj;
            q.x = info.GetSingle("x");
            q.y = info.GetSingle("y");
            q.z = info.GetSingle("z");
            q.w = info.GetSingle("w");
            obj = q;
            return obj;
        }
    }


    public class SaveManager : Singleton<SaveManager>
    {
        private SaveManager()
        {

        }

        public static void CreateTable(string path, string sheetName, Action<ExcelWorksheet> worksheetAction)
        {
            FileInfo excelName = new FileInfo(path);
            if (excelName.Exists)
            {
                //删除旧文件，并创建一个新的 excel 文件。
                excelName.Delete();
                excelName = new FileInfo(path);
            }
            //通过ExcelPackage打开文件
            using (ExcelPackage package = new ExcelPackage(excelName))
            {
                //在 excel 空文件添加新 sheet，并设置名称。
                ExcelWorksheet worksheet = package.Workbook.Worksheets.Add(sheetName);
                worksheetAction?.Invoke(worksheet);
                package.Save(); //储存
                Debug.Log("保存成功：" + path);
            }

        }


        public static void LoadExcelData(string path, string worksheetName, Action<ExcelWorksheet> worksheetAction) {

            FileInfo file = new FileInfo(path);
            if (file.Exists)
            {
                using (ExcelPackage package = new ExcelPackage(file))
                {
                    //在 excel 空文件添加新 sheet，并设置名称。
                    ExcelWorksheet worksheet = package.Workbook.Worksheets[worksheetName];
                    worksheetAction?.Invoke(worksheet);
                }
            }
            else
            {
                Debug.Log($"{path} 不存在");
            }
        }

        /// <summary>
        /// 读取数据
        /// </summary>
        public static T SyncLoadClassData<T>(string filePath) {
            T returnT = JsonTool.SyncLoadClassFile<T>(filePath);
            return returnT;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public static void SyncSaveClassData<T>(string path, T data) {
            JsonTool.SyncSaveClassFile<T>(path, data);            
        }

        public static T SyncLoadData_BinaryFormatter<T>(string filePath) {
            BinaryFormatter bf = new BinaryFormatter();
            SurrogateSelector ss = new SurrogateSelector();
            var streamingContext = new StreamingContext(StreamingContextStates.All);
            ss.AddSurrogate(typeof(Vector3), streamingContext, new Vector3SerializationSurrogate());
            ss.AddSurrogate(typeof(Quaternion), streamingContext, new QuaternionSerializationSurrogate());
            bf.SurrogateSelector = ss;
            Stream sr = File.OpenRead(filePath);
            T data = (T)bf.Deserialize(sr);
            Console.WriteLine(data);
            sr.Dispose();
            return data;
        }


        public static void SyncSaveData_BinaryFormatter<T>(string filePath,T data)
        {
            BinaryFormatter bf = new BinaryFormatter();
            SurrogateSelector ss = new SurrogateSelector();
            var streamingContext = new StreamingContext(StreamingContextStates.All);
            ss.AddSurrogate(typeof(Vector3), streamingContext, new Vector3SerializationSurrogate());
            ss.AddSurrogate(typeof(Quaternion), streamingContext, new QuaternionSerializationSurrogate());
            bf.SurrogateSelector = ss;
            FileStream file=null;
            if (File.Exists(filePath))
            {
                file = File.OpenWrite(filePath);
            }
            else {
                file = File.Create(filePath);
                //file = File.Create(filePath + ".dat");
            }
            
            bf.Serialize(file, data);
            file.Dispose(); 
        }
    }

    public class JsonTool {
        #region  json逐行读写 读写中可能会出现 没有完全覆盖原来的内容的情况 可能需要
        //逐行写入
        public static void SaveToJsonFile<T>(List<T> parts, string path)
        {
            FileStream fs1 = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs1);
            for (int i = 0; i < parts.Count; i++)
            {

                string str = JsonUtility.ToJson(parts[i]);
                sw.WriteLine(str);
            }
            sw.Flush();
            sw.Close();
            fs1.Close();
        }
        //逐行读取
        public static void LoadFromJsonFile<T>(List<T> dataList, string filePath)
        {
            StreamReader sr = new StreamReader(filePath);
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                T partsClass = JToken.Parse(line).ToObject<T>();
                dataList.Add(partsClass);
            }
            sr.Close();
        }

        #endregion

        #region 全部写入或者读取比较安全  但是可能读取大文件的时候可能会比较卡 可以通过协程完成   *后面尝试一下多线程 安卓似乎有点问题
        /// <summary>
        /// 全部写入 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path"></param>
        /// <param name=""></param>
        public static void SyncSaveClassFile<T>(string path, T data)
        {
            string json = JsonConvert.SerializeObject(data, Formatting.Indented);
            FileStream fs1 = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs1);

            fs1.Seek(0, SeekOrigin.Begin);
            fs1.SetLength(0);

            sw.WriteLine(json);
            sw.Flush();
            sw.Close();
            fs1.Close();         
        }
        /// <summary>
        /// 全部读取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="path"></param>
        /// <returns></returns>
        public static T SyncLoadClassFile<T>(string path)
        {
            StreamReader sr = new StreamReader(path);
            string line;
            while ((line = sr.ReadToEnd()) != null)
            {
                T returnT = JsonConvert.DeserializeObject<T>(line);
                sr.Close();

                return returnT;
            }
            return default;
        }

        public static void  AsyncLoadClassFile<T>(string path ,Action<T> onLoaded ) {

        }
        public static void AsyncSaveClassFile<T>(string path, T data, Action onloaded = null) {

        }
        #endregion
    }



    public class XMLTool {
        public static void SaveToXml(string filePath, object sourceObj, Type type, string xmlRootName)
        {
            if (!string.IsNullOrWhiteSpace(filePath) && sourceObj != null)
            {
                type = type != null ? type : sourceObj.GetType();

                using (StreamWriter writer = new StreamWriter(filePath))
                {
                    System.Xml.Serialization.XmlSerializer xmlSerializer = string.IsNullOrWhiteSpace(xmlRootName) ?
                        new System.Xml.Serialization.XmlSerializer(type) :
                        new System.Xml.Serialization.XmlSerializer(type, new XmlRootAttribute(xmlRootName));
                    xmlSerializer.Serialize(writer, sourceObj);
                }
            }
        }

        public static object LoadFromXml(string filePath, Type type)
        {
            object result = null;

            if (File.Exists(filePath))
            {
                using (StreamReader reader = new StreamReader(filePath))
                {
                    System.Xml.Serialization.XmlSerializer xmlSerializer = new XmlSerializer(type);
                    result = xmlSerializer.Deserialize(reader);
                }
            }

            return result;
        }
    }
}

